// extractor.js - 智能字段提取器

import { DEFAULT_FIELDS } from './fields.js';

export class FieldExtractor {
  constructor() {
    this.fields = [];
    this.initialized = false;
  }
  
  async init() {
    if (this.initialized) return;
    
    try {
      this.fields = await this.getAllFields();
      this.initialized = true;
    } catch (e) {
      console.error('字段提取器初始化失败:', e);
    }
  }
  
  // 获取所有字段（包括自定义）
  async getAllFields() {
    const customFields = await this.loadCustomFields();
    return [...DEFAULT_FIELDS, ...customFields];
  }
  
  // 加载自定义字段
  async loadCustomFields() {
    try {
      const result = await chrome.storage.local.get('customFields');
      return result.customFields || [];
    } catch (e) {
      console.error('加载自定义字段失败:', e);
      return [];
    }
  }
  
  // 同步获取字段
  getFieldsSync() {
    if (!this.initialized) {
      console.warn('字段提取器尚未初始化，返回空数组');
      return [];
    }
    return this.fields;
  }
  
  // 主提取方法
  extractFromText(text) {
    try {
      // 尝试解析为JSON
      const jsonObj = JSON.parse(text);
      return this.extractFromJsonObject(jsonObj);
    } catch (e) {
      // 不是JSON，使用原始文本提取
      return this.extractFromRawText(text);
    }
  }
  
  // 从JSON对象提取字段
  extractFromJsonObject(jsonObj) {
    const result = {};
    let extractedCount = 0;
    
    if (!this.initialized) {
      console.warn('字段提取器尚未初始化，无法提取字段');
      return { extractedFields: result, extractedCount };
    }
    
    // 展平JSON对象
    const flatObj = this.flattenObject(jsonObj);
    
    for (const field of this.fields) {
      let value = '';
      
      // 1. 尝试匹配键名
      for (const key in flatObj) {
        if (this.isKeyRelatedToField(key, field)) {
          const fieldValue = flatObj[key];
          value = this.extractFieldValue(fieldValue, field);
          if (value) break;
        }
      }
      
      // 2. 如果键名匹配失败，尝试值匹配
      if (!value) {
        for (const key in flatObj) {
          const fieldValue = flatObj[key];
          value = this.extractFieldValue(fieldValue, field);
          if (value) break;
        }
      }
      
      if (value) {
        result[field.id] = {
          value,
          fieldInfo: field
        };
        extractedCount++;
      }
    }
    
    return { extractedFields: result, extractedCount };
  }
  
  // 从原始文本提取字段 - 优化后的实现
  extractFromRawText(text) {
    const result = {};
    let extractedCount = 0;
    
    if (!this.initialized) {
      console.warn('字段提取器尚未初始化，无法提取字段');
      return { extractedFields: result, extractedCount };
    }
    
    // 处理转义字符
    const normalizedText = text.replace(/\\"/g, '"');
    
    // 创建全局扫描字段列表
    const globallyScannedFields = [
      'timestamp', 'srcIp', 'dstIp', 'srcPort', 'dstPort', 
      'ruleName', 'riskLevel', 'dnsName', 'ioc', 'md5'
    ];
    
    for (const field of this.fields) {
      let value = '';
      let shouldExtract = false;
      
      // 1. 检查是否需要全局扫描此字段
      if (globallyScannedFields.includes(field.id)) {
        shouldExtract = true;
      }
      // 2. 检查字段是否有键名模式（并确保文本中有键名）
      else if (field.keyPatterns && field.keyPatterns.length > 0) {
        shouldExtract = this.hasKeyInText(normalizedText, field);
      }
      // 3. 特殊情况：MAC地址和文件路径需要特别处理
      else if (field.id.includes('Mac') || field.id === 'filePath') {
        shouldExtract = this.hasKeyInText(normalizedText, field);
      }
      
      if (shouldExtract) {
        // 尝试每个值模式
        for (const pattern of field.valuePatterns || field.patterns || []) {
          try {
            const match = normalizedText.match(pattern);
            if (match) {
              let matchedValue = match[1] !== undefined ? match[1] : match[0];
              
              // 特殊处理MAC地址
              if (field.id.includes('Mac') && matchedValue.length < 17) {
                const fullMatch = match[0];
                if (fullMatch.includes(':')) {
                  const macRegex = /([0-9A-Fa-f]{2}[:-]){5}[0-9A-Fa-f]{2}/;
                  const macMatch = fullMatch.match(macRegex);
                  if (macMatch) matchedValue = macMatch[0];
                }
              }
              
              // 处理文件路径字段 - 验证是否是有效路径
              if (field.id === 'filePath') {
                if (!this.isValidFilePath(matchedValue)) {
                  continue; // 跳过无效文件路径
                }
              }
              
              value = matchedValue;
              break;
            }
          } catch (e) {
            console.warn(`正则匹配错误 [${field.id}]:`, pattern, e);
          }
        }
      }
      
      if (value) {
        result[field.id] = {
          value,
          fieldInfo: field
        };
        extractedCount++;
      }
    }
    
    return { extractedFields: result, extractedCount };
  }
  
  // 检查键名是否与字段相关
  isKeyRelatedToField(key, field) {
    const keyLower = key.toLowerCase();
    
    // 1. 检查是否精确匹配字段ID
    if (keyLower === field.id.toLowerCase()) return true;
    
    // 2. 检查是否包含字段ID
    if (keyLower.includes(field.id.toLowerCase())) return true;
    
    // 3. 检查字段是否有键名模式
    if (field.keyPatterns) {
      for (const pattern of field.keyPatterns) {
        if (pattern.test(key)) return true;
      }
    }
    
    // 4. 检查是否包含字段名称中的关键词
    const fieldNameKeywords = field.keywords || [];
    for (const keyword of fieldNameKeywords) {
      if (keyLower.includes(keyword.toLowerCase())) {
        return true;
      }
    }
    
    return false;
  }
  
  // 检查文本中是否存在字段键名
  hasKeyInText(text, field) {
    if (!field.keyPatterns || field.keyPatterns.length === 0) return false;
    
    for (const keyPattern of field.keyPatterns) {
      if (keyPattern.test(text)) return true;
    }
    
    return false;
  }
  
  // 验证文件路径是否有效
  isValidFilePath(path) {
    // 简单验证 - 实际应用中可能需要更复杂的验证
    const validExtensions = [
      '.exe', '.dll', '.js', '.py', '.php', '.jsp', '.class', 
      '.jar', '.txt', '.log', '.config', '.xml', '.json'
    ];
    
    // 检查是否为常见的伪路径（如进程路径）
    const processPathRegex = /\/usr\/local\/bin\/|\/usr\/bin\/|\/bin\//;
    if (processPathRegex.test(path)) return false;
    
    // 检查是否有文件扩展名
    for (const ext of validExtensions) {
      if (path.endsWith(ext)) {
        return true;
      }
    }
    
    // 检查文件路径常用结构
    if (path.includes('/') || path.includes('\\')) {
      return !path.match(/:\d+$/); // 排除包含冒号和数字的路径（如日志头）
    }
    
    return false;
  }
  
  // 从字段值中提取内容
  extractFieldValue(fieldValue, field) {
    if (typeof fieldValue === 'string') {
      return this.extractFromString(fieldValue, field);
    } else if (Array.isArray(fieldValue)) {
      return this.extractFromArray(fieldValue, field);
    } else if (typeof fieldValue === 'object' && fieldValue !== null) {
      return this.extractFromObject(fieldValue, field);
    }
    return '';
  }
  
  // 从字符串提取
  extractFromString(value, field) {
    // 尝试每个值模式
    for (const pattern of field.valuePatterns || field.patterns || []) {
      const match = value.match(pattern);
      if (match) {
        return match[1] !== undefined ? match[1] : match[0];
      }
    }
    return '';
  }
  
  // 从数组提取
  extractFromArray(array, field) {
    for (const item of array) {
      const result = this.extractFieldValue(item, field);
      if (result) return result;
    }
    return '';
  }
  
  // 从对象提取
  extractFromObject(obj, field) {
    for (const key in obj) {
      const result = this.extractFieldValue(obj[key], field);
      if (result) return result;
    }
    return '';
  }
  
  // 展平嵌套对象
  flattenObject(obj, prefix = '') {
    let result = {};
    
    for (const key in obj) {
      const value = obj[key];
      const fullKey = prefix ? `${prefix}.${key}` : key;
      
      if (typeof value === 'object' && value !== null) {
        // 递归展平嵌套对象
        const nested = this.flattenObject(value, fullKey);
        result = { ...result, ...nested };
      } else {
        result[fullKey] = value;
      }
    }
    
    return result;
  }
}